package com.android.support.lib.universal.utils;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;

import com.android.support.lib.universal.views.RoundView;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


/**
 * Created by Administrator on 2017/5/22.
 */

public class UtilConnBitimap {
    private static Activity mActivity;
    private static UtilConnBitimap connBitimap;
    private ThreadPoolExecutor threadPoolExecutor;
    private Map<String, Bitmap> maps;//缓存位图
    private Map<String, Boolean> saveMaps;//确认位图是否保存完成，防止保存和销毁的并发操作。true保存完成，false未保存完成

    private UtilConnBitimap() {
        int corePoolSize = Runtime.getRuntime().availableProcessors() + 2;
        int maxinumPoolSize = corePoolSize * 2 + 1;
        long keepAliveTime = 10;
        TimeUnit unit = TimeUnit.SECONDS;
        BlockingQueue<Runnable> workQueue = new LinkedBlockingDeque<>();
        threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maxinumPoolSize, keepAliveTime, unit, workQueue);
        //Log.e("test", "线程池核心数量:\t" + corePoolSize);
        maps = new HashMap<>();
        saveMaps = new HashMap<>();
    }

    public static UtilConnBitimap getInstance(Activity activity) {
        if (connBitimap == null) {
            connBitimap = new UtilConnBitimap();
        }
        mActivity = activity;
        return connBitimap;
    }

    //设置网络位图
    public void setConnBitmap(final String path, final View view) {
//        if (true) {
//            return;//占用内存2M
//        }
        threadPoolExecutor.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    saveMaps.put(getSaveKey(view), false);
                    //判断缓存位图
                    if (maps != null && maps.containsKey(getKey(path, view))) {
                        Bitmap bitmap = maps.get(getKey(path, view));
                        if (bitmap != null && !bitmap.isRecycled()) {
                            updateView(view, bitmap);
                            saveMaps.put(getSaveKey(view), true);
//                            Log.e("test", "临时缓存");
                            return;
                        } else {
                            maps.remove(getKey(path, view));
//                            Log.e("test", "已经释放");
                        }
                    }
//                    Log.e("test", "么有使用缓存");
                    //判断本地位图
                    Bitmap bm = UtilCache.getInstance(view.getContext()).getAsBitmap(getKey(path, view));//此次对UtilCache进行优化，内部使用了UtilAssets。优化了位图。
                    if (bm != null && !bm.isRecycled()) {
                        updateView(view, bm);
//                        Log.e("test", "本地\tkey:\t" + getKey(path, view) + "\t大小:\t" + bm.getByteCount() / 1024 + "KB");
                        if (maps != null) {
                            maps.put(getKey(path, view), bm);
                        }
                        saveMaps.put(getSaveKey(view), true);
                        return;
                    }
                    URL url = new URL(path);
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    conn.setConnectTimeout(3000);//连接超时设置，绝对有效。一般50毫秒即可连接成功。
                    conn.setRequestMethod("GET");
//                    Log.e("test", "启动：\t" + conn.getResponseCode() + "\t");
                    if (conn.getResponseCode() == 200) {
                        InputStream inputStream = conn.getInputStream();
//                        Bitmap bitmap = BitmapFactory.decodeStream(inputStream, new Rect(0, 0, 0, 0), UtilAssets.getInstance(view.getContext()).getOptions());
                        byte[] b = InputStreamTOByte(inputStream);
                        inputStream.close();
                        inputStream = null;
                        Bitmap bitmap = BitmapFactory.decodeByteArray(b, 0, b.length, UtilAssets.getInstance(view.getContext()).getOptions());
                        b = null;
                        //尽量使用 view.getLayoutParams().width，不要用view.getWidth()【靠不住，有时还会返回0】,但是view.getLayoutParams().width有时也会返回0.如约束布局不能设置match,只能设置0时。就会返回0
                        //Log.e("test", "宽度:\t" + view.getWidth() + "\t宽度：\t" + view.getLayoutParams().width);
                        int width = view.getLayoutParams().width;
                        if (width < view.getWidth()) {
                            width = view.getWidth();
                        }
                        int height = view.getLayoutParams().height;
                        if (height < view.getHeight()) {
                            height = view.getHeight();
                        }
                        bitmap = Bitmap.createScaledBitmap(bitmap, width, height, true);
                        updateView(view, bitmap);
                        //临时缓存
                        if (maps != null) {
                            maps.put(getKey(path, view), bitmap);
//                            Log.e("test", "已经缓存");
                        }
                        //缓存本地位图【再次使用的位图的复制，不是原位图。不要使用原位图，避开出错(同时操控一个位图会奔溃)。放心，复制的都是临时变量，存储完毕，内存会自动消下来。】
                        //UtilCache.getInstance(view.getContext()).put(getKey(path, view), bitmap.copy(Bitmap.Config.RGB_565, true),true);
                        UtilCache.getInstance(view.getContext()).put(getKey(path, view), bitmap);
                        //内存释放,不能释放，释放图片就显示不了了。
//                        if (!bitmap.isRecycled()) {
//                            bitmap.recycle();
//                            bitmap=null;
//                        }
                        saveMaps.put(getSaveKey(view), true);
//                        Log.e("test", "结束:\t" + getKey(path, view) + "\t大小：\t" + bitmapSrc.getByteCount() / 1024 + "KB");
                        System.gc();
                    }
                } catch (Exception e) {
                    saveMaps.remove(getSaveKey(view));
                    Log.e("test", "网络图片请求异常:\t" + e.getMessage());
                }
            }
        });
    }

    final static int BUFFER_SIZE = 4096;

    //InputStream转byte字节，使用字节比使用流更省内存。当然测试发现只对网络输入流有效，一般的本地流就不用转了。转一下还浪费效率。
    public static byte[] InputStreamTOByte(InputStream in) {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] data = new byte[BUFFER_SIZE];
        int count = -1;
        try {
            while ((count = in.read(data, 0, BUFFER_SIZE)) != -1)
                outStream.write(data, 0, count);
        } catch (Exception e) {
            Log.e("test", "流转换字节出错:\t" + e.getMessage());
        }
        data = null;
        return outStream.toByteArray();
    }


    //更新UI
    public void updateView(final View view, final Bitmap bitmap) {
        //防止view.post不执行。【没有附加到当前窗口】
        if (mActivity != null) {
            mActivity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    invalidate(view, bitmap);
                }
            });
        } else {
            view.post(new Runnable() {
                @Override
                public void run() {
                    invalidate(view, bitmap);
                }
            });
        }
    }

    //更新View
    private void invalidate(final View view, final Bitmap bitmap) {
        view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
        //Log.e("test", "执行了");
        if (view instanceof ImageView) {
            recycleImageBitmap((ImageView) view);
            ((ImageView) view).setImageBitmap(bitmap);
        } else if (view instanceof RoundView) {
            ((RoundView) view).recycle();
            ((RoundView) view).setBitmap(bitmap);
        } else {
            recycleBackground(view);
            //view.setBackground(new BitmapDrawable(bitmap));
            view.setBackgroundDrawable(new BitmapDrawable(bitmap));
        }
        System.gc();
    }

    //背景内存释放
    public void recycleBackground(final View view) {
        //Log.e("test","内存释放开始");
        Drawable drawable = view.getBackground();
        if (drawable != null && drawable instanceof BitmapDrawable) {
            BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
            Bitmap bitmap = bitmapDrawable.getBitmap();
            if (bitmap != null && !bitmap.isRecycled()) {
                //Log.e("test", "内存释放:\t" + bitmap.getByteCount() / 1024 / 1024);
                //view.setBackground(null);//置空，很重要
                view.setBackgroundDrawable(null);
                if (saveMaps != null && saveMaps.containsKey(getSaveKey(view)) && !saveMaps.get(getSaveKey(view))) {
                    final Bitmap bm = bitmap;
                    threadPoolExecutor.execute(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                byte b=0;//以防万一。无限循环。
                                while (saveMaps.containsKey(getSaveKey(view)) && !saveMaps.get(getSaveKey(view))&&b<50) {
                                    b++;
                                    //没有保存完成
                                    Thread.sleep(500);
//                               Log.e("test", "销毁前循环判断");
                                }
//                                Log.e("test", "确认销毁2");
                                //保存完成之后再销毁
                                saveMaps.remove(getSaveKey(view));
                                bm.recycle();
                            } catch (Exception e) {
                                Log.e("test", "休眠出错:\t" + e.getMessage());
                            }
                            System.gc();
                        }
                    });
                } else {
//                    Log.e("test", "确认销毁");
                    //保存完成之后再销毁
                    saveMaps.remove(getSaveKey(view));
                    bitmap.recycle();
                    bitmap = null;
                }
            }
        }
        drawable = null;
        System.gc();
    }

    //回收ImageView里面的Src图片,最好调用一下。保持好习惯。
    public void recycleImageBitmap(final ImageView view) {
        Drawable drawable = view.getDrawable();
        if (drawable != null && drawable instanceof BitmapDrawable) {
            BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
            Bitmap bitmap = bitmapDrawable.getBitmap();
            if (bitmap != null) {
                //Log.e("test", "内存释放2:\t" + bitmap.getByteCount() / 1024 / 1024);
                if (saveMaps != null && saveMaps.containsKey(getSaveKey(view)) && !saveMaps.get(getSaveKey(view))) {
                    final Bitmap bm = bitmap;
                    threadPoolExecutor.execute(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                byte b=0;//以防万一。无限循环。
                                while (saveMaps.containsKey(getSaveKey(view)) && !saveMaps.get(getSaveKey(view))&&b<50) {
                                    b++;
                                    //没有保存完成
                                    Thread.sleep(500);
//                               Log.e("test", "销毁前循环判断");
                                }
                                //                            Log.e("test", "确认销毁2");
                                //保存完成之后再销毁
                                saveMaps.remove(getSaveKey(view));
                                bm.recycle();
                            } catch (Exception e) {
                                Log.e("test", "休眠出错:\t" + e.getMessage());
                            }
                            System.gc();
                        }
                    });
                } else {
//                    Log.e("test", "确认销毁");
                    //保存完成之后再销毁
                    saveMaps.remove(getSaveKey(view));
                    bitmap.recycle();
                    bitmap = null;
                }
                view.setImageBitmap(null);
            }
        }
        drawable = null;
        System.gc();
    }

    //缓存Bitmap的Key值,确保了绝对唯一。
    public String getKey(String path, View view) {
        int width = view.getLayoutParams().width;
        if (width < view.getWidth()) {
            width = view.getWidth();
        }
        int height = view.getLayoutParams().height;
        if (height < view.getHeight()) {
            height = view.getHeight();
        }
        return path + width + "" + height;
    }

    //获取保存的map键值
    public String getSaveKey(View view) {
        return view.getId() + "" + view.hashCode();
    }
}
